home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
Book Chapters
/
03 - Advanced Graphics
/
Example 5
/
sprite.c
< prev
next >
Wrap
Text File
|
1995-02-27
|
14KB
|
470 lines
//
// File: sprite.c
//
// This file contains the routines to draw the sprites
//
// 2/19/95 -- Created by Mick
//
// include files
#include "global.h"
#include "sprite.h"
#include "main.h"
// defines for this file
#define kEndShapeToken 0L // the end of shape maker
#define kLineStartToken 1L // the line start marker
#define kDrawPixelsToken 2L // the draw run marker
#define kSkipPixelsToken 3L // the skip pixels marker
// global function declarations
tSpriteInfo *loadSprite( signed short inSpriteResID );
void disposeSprite( tSpriteInfo *inSpriteInfo );
void startSpriteDraw( Rect *inClipRect, PixMapHandle inDestPixMap );
void endSpriteDraw( void );
void drawSprite( tSpriteInfo *inSpriteInfo, Point inWhere );
// global data owned by this file
// local function declarations
static void renderSpriteClipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect );
static void renderSpriteUnclipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect );
// static data
Rect sClipRect; // the rectangle to clip to
PixMapHandle sDestPixMap; // where we are going to draw this data
unsigned char *sBaseAddr; // the base address of the pixmap
unsigned long sRowBytes; // the row bytes of the pixmap
// functions
//
// loadSprite -
//
// Loads/allocates all the data for a sprite.
//
tSpriteInfo *loadSprite( signed short inSpriteResID )
{
tSpriteInfo *newSprite; // the new sprite data
// create the sprite info record
newSprite = ( tSpriteInfo * )NewPtr( sizeof( tSpriteInfo ) );
// load the sprite
newSprite->fSpriteData = GetResource( kSpriteResType, inSpriteResID );
HNoPurge( newSprite->fSpriteData );
if ( newSprite->fSpriteData == ( Handle )kNil )
{
// if it did not load, drop into the debugger -- real programs would have error checking
Debugger();
}
// copy its bounds rect
newSprite->fSpriteRect = **( ( Rect ** )( newSprite->fSpriteData ) );
// return the new sprite!
return newSprite;
}
//
// disposeSprite -
//
// Disposes/releases all the memory used in a sprite
//
void disposeSprite( tSpriteInfo *inSpriteInfo )
{
// dump the sprite resource
ReleaseResource( inSpriteInfo->fSpriteData );
// free the structure
DisposePtr( ( Ptr )inSpriteInfo );
}
//
// startSpriteDraw -
//
// Prepare the sprite draw. Assumes that the port is set to the destination port.
//
void startSpriteDraw( Rect *inClipRect, PixMapHandle inDestPixMap )
{
// set the clip region to be the passed in rect
sClipRect = *inClipRect;
// save the pix map info (so we can use it)
sDestPixMap = inDestPixMap;
// get info from the pix map
sBaseAddr = ( unsigned char * )GetPixBaseAddr( sDestPixMap );
sRowBytes = ( *sDestPixMap )->rowBytes & 0x3fff;
}
//
// endSpriteDraw -
//
// End the sprite draw sequence.
//
void endSpriteDraw( void )
{
}
//
// drawSprite -
//
// Draw the sprite in the port.
//
void drawSprite( tSpriteInfo *inSpriteInfo, Point inWhere )
{
Rect destRect; // where we want to draw the sprite
// calculate the destination rect
destRect = inSpriteInfo->fSpriteRect;
OffsetRect( &destRect, inWhere.h, inWhere.v );
// determine if the spite needs to be drawn at all
if( destRect.top >= sClipRect.bottom || destRect.bottom <= sClipRect.top ||
destRect.left >= sClipRect.right || destRect.right <= sClipRect.left )
{
// no need to draw, goodbye
return;
}
// determine if the sprite will be clipped
if ( destRect.top < sClipRect.top || destRect.bottom > sClipRect.bottom ||
destRect.left < sClipRect.left || destRect.right > sClipRect.right )
{
// handle the clipped case
renderSpriteClipped( inSpriteInfo, &destRect );
}
else
{
// handle the unclipped case
renderSpriteUnclipped( inSpriteInfo, &destRect );
}
}
//
// renderSpriteClipped -
//
// Draw the spite, deal with clipping.
//
void renderSpriteClipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect )
{
Rect clipRect; // the rect that defines the clipped shape
unsigned char *rowStart; // the pointer to the start of this row
unsigned char *srcPtr; // the current position in the sprite data
unsigned char *destPtr; // the current position in the destination pixmap
unsigned long miscCounter; // a counter for various purposes
unsigned long extraCounter; // a counter for right clippling purposes ( how much extra was there? )
unsigned long tokenOp; // the op code from the token
unsigned long tokenData; // the data from the token
unsigned char exitFlag; // should we exit from the loop?
unsigned long yCount; // how many lines down in the shape are we?
unsigned long xCount; // where are we in this line?
// create a clipped rect in the coordinates of the sprite
clipRect.left = inDestRect->left < sClipRect.left ? sClipRect.left - inDestRect->left : 0;
clipRect.right = inDestRect->right > sClipRect.right ? sClipRect.right - inDestRect->left : inDestRect->right - inDestRect->left;
clipRect.top = inDestRect->top < sClipRect.top ? sClipRect.top - inDestRect->top : 0;
clipRect.bottom = inDestRect->bottom > sClipRect.bottom ? sClipRect.bottom - inDestRect->top : inDestRect->bottom - inDestRect->top;
// set up the counters
yCount = 0;
// determine characteristics about the pixmap
rowStart = sBaseAddr + inDestRect->top * sRowBytes + inDestRect->left;
// move to the right place in the shape ( just past the size rect )
srcPtr = ( unsigned char * )( ( *( inSpriteInfo->fSpriteData ) ) + sizeof( Rect ) );
// loop until we are done
exitFlag = kFalse;
while( !exitFlag )
{
// get a token
tokenOp = ( *( ( unsigned long * )srcPtr ) ) >> 24;
tokenData = ( *( ( unsigned long * )srcPtr ) ) & 0x00ffffff;
srcPtr += sizeof( unsigned long );
// depending on the token
switch( tokenOp )
{
case kDrawPixelsToken:
miscCounter = tokenData;
extraCounter = 0;
// if we need to, clip to the left
if( xCount < clipRect.left )
{
// if this run does not appear at all, don't draw it
if ( miscCounter < clipRect.left - xCount )
{
destPtr += miscCounter;
srcPtr += miscCounter;
srcPtr += ( ( tokenData & 3L ) == 0 ) ? 0 : ( 4 - ( tokenData & 3L ) );
xCount += miscCounter;
break;
}
else
{
// if it does, skip to where we can draw
miscCounter -= clipRect.left - xCount;
destPtr += clipRect.left - xCount;
srcPtr += clipRect.left - xCount;
xCount += clipRect.left - xCount;
}
}
// if we need to, clip to the right
if ( xCount + miscCounter > clipRect.right )
{
// if this run does not appear at all, skip it
if ( xCount > clipRect.right )
{
destPtr += miscCounter;
srcPtr += miscCounter;
srcPtr += ( ( tokenData & 3L ) == 0 ) ? 0 : ( 4 - ( tokenData & 3L ) );
xCount += miscCounter;
break;
}
else
{
// if it does, setup to draw what we can
extraCounter = miscCounter;
miscCounter -= ( xCount + miscCounter ) - clipRect.right;
extraCounter -= miscCounter;
}
}
// adjust xCount for the run
xCount += miscCounter;
// move data in the biggest chunks we can find
#ifdef powerc
// move in doubles while we can
while( miscCounter >= sizeof( double ) )
{
*( ( double * )destPtr ) = *( ( double * )srcPtr );
destPtr += sizeof( double );
srcPtr += sizeof( double );
miscCounter -= sizeof( double );
}
// move a long if we can
if ( miscCounter >= sizeof( unsigned long ) )
{
*( ( unsigned long * )destPtr ) = *( ( unsigned long * )srcPtr );
destPtr += sizeof( unsigned long );
srcPtr += sizeof( unsigned long );
miscCounter -= sizeof( unsigned long );
}
#else
// move in longs while we can
while( miscCounter >= sizeof( unsigned long ) )
{
*( ( unsigned long * )destPtr ) = *( ( unsigned long * )srcPtr );
destPtr += sizeof( unsigned long );
srcPtr += sizeof( unsigned long );
miscCounter -= sizeof( unsigned long );
}
#endif
// move a short if we can
if ( miscCounter >= sizeof( unsigned short ) )
{
*( ( unsigned short * )destPtr ) = *( ( unsigned short * )srcPtr );
destPtr += sizeof( unsigned short );
srcPtr += sizeof( unsigned short );
miscCounter -= sizeof( unsigned short );
}
// move a char if we can
if ( miscCounter >= sizeof( unsigned char ) )
{
*( ( unsigned char * )destPtr ) = *( ( unsigned char * )srcPtr );
destPtr += sizeof( unsigned char );
srcPtr += sizeof( unsigned char );
miscCounter -= sizeof( unsigned char );
}
// adjust for right clipping
destPtr += extraCounter;
srcPtr += extraCounter;
xCount += extraCounter;
// adjust for the padding
srcPtr += ( ( tokenData & 3L ) == 0 ) ? 0 : ( 4 - ( tokenData & 3L ) );
break;
case kSkipPixelsToken:
destPtr += tokenData;
xCount += tokenData;
break;
case kLineStartToken:
// if this line is above the clip rect, skip to the next line
if( yCount < clipRect.top )
{
srcPtr += tokenData;
}
// set up the destination pointer
destPtr = rowStart;
rowStart += sRowBytes;
// move the yCounter
yCount++;
// reset the xCounter
xCount = 0;
// if we have hit the bottom clip, exit the loop
if ( yCount > clipRect.bottom )
{
exitFlag = kTrue;
}
break;
case kEndShapeToken:
// signal a loop exit
exitFlag = kTrue;
break;
default:
// we should never get here
Debugger();
break;
}
}
}
//
// renderSpriteUnclipped -
//
// Draw the sprite, no clipping needed
//
void renderSpriteUnclipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect )
{
unsigned char *rowStart; // the pointer to the start of this row
unsigned char *srcPtr; // the current position in the sprite data
unsigned char *destPtr; // the current position in the destination pixmap
unsigned long miscCounter; // a counter for various purposes
unsigned long tokenOp; // the op code from the token
unsigned long tokenData; // the data from the token
unsigned char exitFlag; // should we exit from the loop?
// determine characteristics about the pixmap
rowStart = sBaseAddr + inDestRect->top * sRowBytes + inDestRect->left;
// move to the right place in the shape ( just past the size rect )
srcPtr = ( unsigned char * )( ( *( inSpriteInfo->fSpriteData ) ) + sizeof( Rect ) );
// loop until we are done
exitFlag = kFalse;
while( !exitFlag )
{
// get a token
tokenOp = ( *( ( unsigned long * )srcPtr ) ) >> 24;
tokenData = ( *( ( unsigned long * )srcPtr ) ) & 0x00ffffff;
srcPtr += sizeof( unsigned long );
// depending on the token
switch( tokenOp )
{
case kDrawPixelsToken:
miscCounter = tokenData;
// move data in the biggest chunks we can find
#ifdef powerc
// move in doubles while we can
while( miscCounter >= sizeof( double ) )
{
*( ( double * )destPtr ) = *( ( double * )srcPtr );
destPtr += sizeof( double );
srcPtr += sizeof( double );
miscCounter -= sizeof( double );
}
// move a long if we can
if ( miscCounter >= sizeof( unsigned long ) )
{
*( ( unsigned long * )destPtr ) = *( ( unsigned long * )srcPtr );
destPtr += sizeof( unsigned long );
srcPtr += sizeof( unsigned long );
miscCounter -= sizeof( unsigned long );
}
#else
// move in longs while we can
while( miscCounter >= sizeof( unsigned long ) )
{
*( ( unsigned long * )destPtr ) = *( ( unsigned long * )srcPtr );
destPtr += sizeof( unsigned long );
srcPtr += sizeof( unsigned long );
miscCounter -= sizeof( unsigned long );
}
#endif
// move a short if we can
if ( miscCounter >= sizeof( unsigned short ) )
{
*( ( unsigned short * )destPtr ) = *( ( unsigned short * )srcPtr );
destPtr += sizeof( unsigned short );
srcPtr += sizeof( unsigned short );
miscCounter -= sizeof( unsigned short );
}
// move a char if we can
if ( miscCounter >= sizeof( unsigned char ) )
{
*( ( unsigned char * )destPtr ) = *( ( unsigned char * )srcPtr );
destPtr += sizeof( unsigned char );
srcPtr += sizeof( unsigned char );
miscCounter -= sizeof( unsigned char );
}
// adjust for the padding
srcPtr += ( ( tokenData & 3L ) == 0 ) ? 0 : ( 4 - ( tokenData & 3L ) );
break;
case kSkipPixelsToken:
destPtr += tokenData;
break;
case kLineStartToken:
// set up the destination pointer
destPtr = rowStart;
rowStart += sRowBytes;
break;
case kEndShapeToken:
// signal a loop exit
exitFlag = kTrue;
break;
default:
// we should never get here
Debugger();
break;
}
}
}